package com.github.m6d21.sso.support.aspect;

import static com.github.m6d21.sso.support.constant.TokenConstant.KEY_TOKEN;

import com.github.m6d21.sso.common.util.CookieBuilder;
import com.github.m6d21.sso.core.annotation.Login;
import com.github.m6d21.sso.model.user.entity.User;
import com.github.m6d21.sso.support.model.SsoTokenWrapper;
import com.github.m6d21.sso.support.session.SsoSessionHolder;
import com.github.m6d21.sso.support.token.SsoTokenHelper;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint;
import org.springframework.aop.framework.ReflectiveMethodInvocation;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

/**
 *<p>
 *登录切面
 *</p>
 *
 * @author liuyang
 * @date 2018/12/8 Sat 22:59:00
 * @since 1.0.0
 */
@Aspect
@ControllerAdvice
public class LoginAspect {

    private static final Logger LOG = LoggerFactory.getLogger(LoginAspect.class);

    @Value("${sso.token.expire}")
    private int cookieExpire = 600;

    @Pointcut("@annotation(com.github.m6d21.sso.core.annotation.Login)")
    public void pcLogin() {
    }

    @Before("pcLogin()")
    @SuppressWarnings("all")
    public void doBeforeLogin(JoinPoint joinPoint) {
        try {
            MethodInvocationProceedingJoinPoint methodJoinPoint = (MethodInvocationProceedingJoinPoint) joinPoint;
            Field proxy = methodJoinPoint.getClass().getDeclaredField("methodInvocation");
            proxy.setAccessible(true);
            ReflectiveMethodInvocation j = (ReflectiveMethodInvocation) proxy.get(methodJoinPoint);
            Method method = j.getMethod();
            Annotation annotation = method.getAnnotation(Login.class);
            if (annotation != null) {
                Login login = (Login) annotation;
                this.cookieExpire = (int) login.cookieExpire();
            }
        } catch (Exception e) {
            LOG.error("doBeforeLogin： 解析注解错误{}", e);
        }
    }

    @AfterReturning(pointcut = "pcLogin()", returning = "result")
    @SuppressWarnings("all")
    public void doAfterReturning(Object result) {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        if (result == null || !(result instanceof User)) {
            return;
        }
        HttpServletRequest request = attributes.getRequest();
        HttpServletResponse response = attributes.getResponse();
        String domain = request.getServerName();
        User user = (User) result;
        if(user!=null) {
            SsoTokenWrapper ssoTokenWrapper = SsoTokenHelper.createToken();
            ssoTokenWrapper.setUid(user.getId() + "");
            ssoTokenWrapper.setUsername(user.getUsername());
            ssoTokenWrapper.setDisplayName(user.getDisplayName());
            ssoTokenWrapper.setPhone(user.getPhone());
            ssoTokenWrapper.setDomain(domain);
            SsoTokenHelper.commit(ssoTokenWrapper);

            //session绑定到当前线程
            SsoSessionHolder.addAttributes(ssoTokenWrapper.getAttributes());
            SsoSessionHolder.addAttribute("token", ssoTokenWrapper.getToken());
            SsoSessionHolder.addAttribute("uid", ssoTokenWrapper.getUid());
            SsoSessionHolder.addAttribute("username", ssoTokenWrapper.getUsername());
            SsoSessionHolder.addAttribute("displayName", ssoTokenWrapper.getDisplayName());
            SsoSessionHolder.addAttribute("phone", ssoTokenWrapper.getPhone());

            response.addHeader(KEY_TOKEN, ssoTokenWrapper.getToken());
            Cookie cookie = CookieBuilder.cookie(KEY_TOKEN, ssoTokenWrapper.getToken()).path("/").maxAge(cookieExpire)
                .build();
            response.addCookie(cookie);
        }
    }
}
